CodePipeline で承認プロセスを設けた Terraform workspace の CI/CD パイプライン実装
先日、CodeCommit への push をトリガーに terraform apply
をサクッと実行するシンプルなパイプラインの記事を投稿しました。
今回はもうちょっと発展させて以下のような要件を取り込んでみたいと思います。
- terraform workspace 環境でも使えるようにしたい
- 本番環境は
terraform apply
の前に承認者による承認プロセスを入れたい
イメージは以下のとおりです。
開発環境向け
1-1. develop
ブランチへ push
1-2. dev
workspace に terraform apply
を実行
本番環境向け
2-1. develop
ブランチから master
ブランチへ merge
2-2. prod
workspace で terraform plan
を実行
2-3. 承認者に後続処理の承認要求をメール通知
2-4. 本番用パイプラインで後続処理を「承認」
2-5. prod
workspace で terraform apply
を実行
概要がわかっていただけたかと思いますので、それではパイプラインを構築していきます。
Terraform Backend の作成
S3 および DynamoDB を使った Terraform Backend ですが、この部分は変更がありませんので前回の記事を参照ください。
Terraform workspace の作成
workspace の作成はパイプラインに入れる必要はありません。以下のコマンドをローカル実行し、事前に作成しておきます。
$ terraform workspace new dev Created and switched to workspace "dev"! You're now on a new, empty workspace. Workspaces isolate their state, so if you run "terraform plan" Terraform will not see any existing state for this configuration. $ terraform workspace new prod Created and switched to workspace "prod"! You're now on a new, empty workspace. Workspaces isolate their state, so if you run "terraform plan" Terraform will not see any existing state for this configuration. $ terraform workspace list default dev * prod
以上で OK です。ちなみに Terraform workspace 環境の場合、S3 や DynamoDB の backend は以下のように env:
階層が追加され、tfstate も LockID も分離して管理されます。
CodeCommit の作成
こちらも手順としては変更ありませんので前回の記事を参照ください。
構成としては、develop
および master
ブランチの 2 つが存在する状態です。
dev 用 CI/CD パイプライン
CodePipeline の作成
基本的には前回の記事と同じなので、前回手順を参考にすすめてください。一部、buildspec.yml
の書き方を変えたので、[Build -optional] での環境変数のみ、下記のように変更しています。(前回の手順だと、[CodePipeline 作成]の手順12.の箇所です)
Name | Value | Type | 説明 |
---|---|---|---|
TF_VERSION | 0.12.19 | Plaintext | Terraform バージョン |
TF_CMD | apply | Plaintext | terraform コマンド |
TF_WS | dev | Plaintext | workspace 名 |
TF_OPT | -input=false -auto-approve -no-color | Plaintext | terraform コマンドのオプション |
前回までは Build プロジェクトのなかで terraform plan
と terraform apply
を実行してたのですが、開発環境においては事前に自分で terraform plan
流してるだろうし、ダメならコケて終わりなので必要ないかと思って外しました。
また、terraform plan
と terraform apply
ではオプションが異なるのですが buildspec.yml
を共通化したかったので、コマンドオプションも TF_OPT
環境変数に入れて渡すことにしました。
workspace 対応のために、workspace 名の指定が必要となりましたので、こちらは TF_WS
に入れることにしました。buildspec.yml
は以下のとおり。
version: 0.2 phases: install: runtime-versions: docker: 18 commands: - yum install unzip -y - wget https://releases.hashicorp.com/terraform/"$TF_VERSION"/terraform_"$TF_VERSION"_linux_amd64.zip - unzip terraform_"$TF_VERSION"_linux_amd64.zip - mv terraform /usr/local/bin/ pre_build: commands: - terraform init -input=false -no-color - terraform workspace select $TF_WS -no-color build: commands: - terraform $TF_CMD $TF_OPT post_build: commands: - echo terraform $TF_CMD completed on `date`
CodeBuild 用の IAM ロール設定
前回同様に、今回も CodeBuild 用 IAM ロールに AdministratorAccess
ポリシーをアタッチして検証しました。
prod 用 CI/CD パイプライン
CodePipeline の作成
dev 用のパイプラインは 2 つのステージ(ソースアーティファクトの作成、terraform apply
)のみでしたが、prod 用は以下のような 4 つのステージを作成していきます。
- ソースアーティファクトの作成
terraform plan
を実行- 承認プロセス
terraform apply
を実行
それでは Create pipeline
から開始します。
1. CodePipeline 管理コンソールから Create pipeline
をクリック
2. パイプライン名を入力し、New service role
を選択して Next
を選択
3. ソースプロバイダーに AWS CodeCommit
を選択。該当のリポジトリと、master
ブランチを指定
4. 検出オプションは Amazon CloudWatch Events (recommended)
を選択して Next
を選択
5. ビルドプロバイダーに AWS CodeBuild
を選択
6. Create Project
をクリックし、ビルドプロジェクトを作成(別のウィンドウが起動します)
7. プロジェクト名を入力
8. [Environment Image]で Managed image
を選択し、以下のように選択
- Operating system:
Amazon Linux2
- Runtime:
Standard
- Image:
aws/codebuild/amazonlinux2-x86_64-standard:2.0
- Image version:
Always use the latest image for this runtime version
- Environment type:
Linux
9. [Privileged] の下にあるチェックボックスにチェックを入れ、New service role
を選択
10. Buildspec のセクションは、Use a buildsped file
を選択
11. Log セクションで、CloudWatch logs
にチェックを入れ Continue to CodepiPeline
をクリック
12. 元のウィンドウに戻り、[Environment variables] で以下の環境変数を設定し Next
をクリック
Name | Value | Type | 説明 |
---|---|---|---|
TF_VERSION | 0.12.19 | Plaintext | Terraform バージョン |
TF_CMD | plan | Plaintext | terraform コマンド |
TF_WS | prod | Plaintext | workspace 名 |
TF_OPT | -input=false -lock=false -no-color | terraform コマンドのオプション |
13. CodeDeploy は不要ですので、Skip deploy stage
をクリック
14. Create pipeline
でパイプラインを作成
CodeBuild 用の IAM ロール設定
- IAM 管理コンソールを開き、[Roles]から先ほど CodeBuild 設定のなかで作成した IAM ロールを検索し、IAM ロール名をクリック
- [Permissions]タブを開き、[Attach policies]をクリック
- ビルド対象のリソース管理に必要なポリシーをアタッチ。(今回も AdministratorAccess をアタッチしましたが、必要に応じて必要な権原に絞り込んでください)
SNS 設定
次に、承認要求のメールを通知するための SNS 設定を行います。
1. SNS 管理コンソールを開き、[Topics] から Create topic
をクリック
2. トピック名 を入力し、Create topic
をクリック
3. トピック一覧に戻り、作成したばかりのトピックをクリック
4. Subscriptions
タブから Create subscription
をクリック
5. 3.で作成したトピック、プロトコル(Email)、Endpiont(Email アドレス) を指定し、Create subscription
をクリック
6. Confirm メールが届くので、リンクをクリックし Confirm する
承認ステージの追加
CodePipeline 管理コンソールに戻り、prod 用パイプラインに承認ステージを追加します。
1. CodePipeline 管理コンソールから prod 用パイプラインを開き、Edit
をクリック
2. [Build] ステージの下にある Add Stage
をクリック
3. ステージ名を入力し、Add stage
をクリック(私は terraform-apply-prod-approval
としました)
4. 作成したステージ内の Add action group
をクリック
5. アクション名を入力、アクションプロバイダで Manual approval
を選択。SNS topic ARN は先ほど作成したものを指定し、必要に応じてコメントを入力し、Done
terraform apply ステージの追加
承認プロセスが完了した後の terraform apply
を実行するステージを設定します。
1. CodePipeline 管理コンソールから prod 用パイプラインを開き、Edit
をクリック
2. 承認ステージの下にある Add Stage
をクリック
3. ステージ名を入力し、Add stage
をクリック(私は terraform-apply-prod
としました)
4. 作成したステージ内の Add action group
をクリック
5. アクション名を入力、アクションプロバイダで AWS CodeBuild
を選択。その後は、基本的には dev 環境と同じように Build project の設定を進めます。Add environment variable
については、以下のように設定し、Done
Name | Value | Type | 説明 |
---|---|---|---|
TF_VERSION | 0.12.19 | Plaintext | Terraform バージョン |
TF_CMD | apply | Plaintext | terraform コマンド |
TF_WS | prod | Plaintext | workspace 名 |
TF_OPT | -input=false -auto-approve -no-color | Plaintext | terraform コマンドのオプション |
これでパイプラインとしては完成です。
CI/CD パイプラインの検証
dev 環境に push
前回の記事と同じ config.tf
を含めて、以下のファイルを準備します。
- config.tf
- buildspec.yml (上記参照)
- s3.tf (今回も S3 バケットの作成で動作確認します)
バケット名が重複しないように terraform.workspace
を付与しています。実行する workspace によって dev
や prod
の値が入ります。
resource "aws_s3_bucket" "cm-terraform-000" { bucket = "cm-terraform-${terraform.workspace}-000" acl = "private" }
terraform { required_version = ">= 0.12.0" backend "s3" { encrypt = true bucket = "terraform-tfstate" dynamodb_table = "terraform-state-lock" key = "terraform.tfstate" region = "ap-northeast-1" } }
develop
環境に push します。
marumo.atsushi@:~/Project/terraform-cicd (develop) $ ls -l total 40 -rw-r--r-- 1 marumo.atsushi staff 575 1 22 18:39 buildspec.yml -rw-r--r-- 1 marumo.atsushi staff 336 1 21 09:22 config.tf -rw-r--r-- 1 marumo.atsushi staff 121 1 24 05:49 s3.tf $ git push Warning: Permanently added 'git-codecommit.ap-northeast-1.amazonaws.com,52.119.218.16' (RSA) to the list of known hosts. Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 307 bytes | 307.00 KiB/s, done. Total 3 (delta 2), reused 0 (delta 0) To ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/terraform-cicd 54edaa2..cf564d9 develop -> develop
dev 用パイプラインの確認
dev 用の CodePipeline が正常に実行されていることを確認します。
S3 バケット cm-terraform-dev-000
が作成されていることを確認します。
dev 用のパイプラインが正常に動作していることが確認できましたね。
develop → master への merge
それでは prod 用のパイプラインを動作させるために、develop
ブランチを master
ブランチに merge しましょう。
CodeCommit 管理コンソールからリポジトリの develop
ブランチを開き、Create pull request
をクリック。
Destination に master
、Source に develop
を指定し、Title および必要に応じて Description を入力し、Create pull request
をクリック。
作成したプルリクエストを開き、Merge
をクリック。
Merge strategy は任意のものを指定します。merge 後にブランチを削除したくない場合は Delete source branch develop after merging?
のチェックを外し、Merge pull request
をクリック。
これで prod 用のパイプラインがトリガーされることになります。
prod 用パイプラインの確認
prode 用の CodePipeline を開くと、master
ブランチへの merge によってパイプラインが動作しているはずです。Build(terraform plan) ステージが実行された後、承認ステージの terraform-apply-prod-approval で Pending していることが判りますね。
SNS トピックのサブスクリプションで指定したアドレスに以下のようなメールが届きます。
リンクをクリックすると CodePipeline 管理コンソールが開きますので、Build ステージの terraform_plan
の Details
をクリックし、変更内容を確認します。
変更内容に問題がなければ、承認ステージ内の Review
をクリック。必要に応じてコメントを入力し、Approve
をクリック。
承認後、terraform_apply ステージが実行されていることを確認します。
S3 バケット cm-terraform-prod-000
が作成されていることを確認します。
正常に作成されていることが確認できましたね!検証は以上です!
さいごに
Terraform workspace を利用した環境での CI/CD パイプラインを試してみました。本番環境へのデプロイは、必要最低限の安全措置を承認プロセスを設けることで確保しています。
これが正解というワケではなく、あくまで 1 つの案として参考にしていただければと思います。
以上!大阪オフィスの丸毛(@marumo1981)でした!